export class Point {
  x;
  y;
  constructor(x, y, round) {
    this.x = round ? Math.round(x) : x;
    this.y = round ? Math.round(y) : y;
    // return this;
  }
  clone() {
    return new Point(this.x, this.y);
  }
  floor() {
    return this.clone()._floor();
  }
  unscaleBy(point) {
    return new Point(this.x / point.x, this.y / point.y);
  }
  distanceTo(point) {
    point = toPoint(point);

    const x = point.x - this.x,
      y = point.y - this.y;

    return Math.sqrt(x * x + y * y);
  }
  ceil() {
    return this.clone()._ceil();
  }
  scaleBy(point) {
    return new Point(this.x * point.x, this.y * point.y);
  }
  round() {
    return this.clone()._round();
  }

  _round() {
    this.x = Math.round(this.x);
    this.y = Math.round(this.y);
    return this;
  }
  _ceil() {
    this.x = Math.ceil(this.x);
    this.y = Math.ceil(this.y);
    return this;
  }

  add(point) {
    // non-destructive, returns a new point
    return this.clone()._add(toPoint(point));
  }

  _add(point) {
    // destructive, used directly for performance in situations where it's safe to modify existing point
    this.x += point.x;
    this.y += point.y;
    return this;
  }
  subtract(point) {
    return this.clone()._subtract(toPoint(point));
  }
  _subtract(point) {
    this.x -= point.x;
    this.y -= point.y;
    return this;
  }
  multiply(num) {
    return this.clone()._multiply(num);
  }
  _multiply(num) {
    this.x *= num;
    this.y *= num;
    return this;
  }
  divideBy(num) {
    return this.clone()._divideBy(num);
  }
  _divideBy(num) {
    this.x /= num;
    this.y /= num;
    return this;
  }

  _floor() {
    this.x = Math.floor(this.x);
    this.y = Math.floor(this.y);
    return this;
  }
}

export function toPoint(x, y, round) {
  if (x instanceof Point) {
    return x;
  }
  if (Array.isArray(x)) {
    return new Point(x[0], x[1]);
  }
  if (x === undefined || x === null) {
    return x;
  }
  if (typeof x === "object" && "x" in x && "y" in x) {
    return new Point(x.x, x.y);
  }
  return new Point(x, y, round);
}
